package ejb;

import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.lang.Math;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.NonUniqueResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import utils.ZaraException;

import entidadesBD.Articulo;
import entidadesBD.ArticulosPALC;
import entidadesBD.CentroDistribucion;
import entidadesBD.PALC;
import entidadesBD.Tienda;
import entidadesVO.ArticuloVO;
import entidadesVO.ArticulosPALCVO;
import entidadesVO.PALCVO;
import entidadesVO.TiendaVO;

public @Stateless class AdministradorPALCBean implements AdministradorPALC {

	@PersistenceContext(unitName="zara")
	private EntityManager manager;

	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public PALCVO setPALC(PALCVO palcVO) throws ZaraException{
		
		PALC palc = new PALC();
		manager.persist(palc);
		palc.setFechaPALC(palcVO.getFechaPALC());
		
		Tienda tienda = null;
		
		try{
			tienda = getTiendaInstance(palcVO.getTienda().getNombreTienda());
		}catch (NonUniqueResultException e){
			
			manager.remove(palc);
			
			throw new ZaraException(e.toString());
		}finally{
			if (tienda != null){
				palc.setTienda(tienda);
			}else{
				
				manager.remove(palc);
				
				throw new ZaraException("No existe una Tienda para el nombre: " + palcVO.getTienda().getNombreTienda());
			}
		}
		
		Object[] articulosPALCList = palcVO.getArticulosPALC().toArray();
		
		for (int i = 0; i < articulosPALCList.length; i++){
			ArticulosPALC articulosPALC = new ArticulosPALC();
			articulosPALC.setArticulosPALC((ArticulosPALCVO)articulosPALCList[i]);
			
			Query query = manager.createQuery("SELECT a FROM Articulo a WHERE a.referencia LIKE :referencia");
			query.setParameter("referencia", ((ArticulosPALCVO)articulosPALCList[i]).getArticulo().getReferencia());
					
			Articulo articulo = null;
					
			try{
				articulo = (Articulo)query.getSingleResult();
			}catch (NonUniqueResultException e){
					
				manager.remove(palc);
					
				throw new ZaraException(e.toString());
			}finally{
				if(articulo == null){
						
					manager.remove(palc);
													
					throw new ZaraException("No existe un Articulo para la referencia: " + ((ArticulosPALCVO)articulosPALCList[i]).getArticulo().getReferencia());
				}else{							
					Object[] centrosDistribucionList = articulo.getCentrosDeDistribucion().toArray();
					
					CentroDistribucion cd_mas_cercano = (CentroDistribucion) centrosDistribucionList[i];
					
					float distancia_mas_cercano = getDistancia(palc.getTienda(), cd_mas_cercano);
					
					for(int k = 1; k < centrosDistribucionList.length; k++){
						float distancia = getDistancia(palc.getTienda(), (CentroDistribucion) centrosDistribucionList[k]);
						
						if (distancia < distancia_mas_cercano){
							distancia_mas_cercano = distancia;
							cd_mas_cercano = (CentroDistribucion) centrosDistribucionList[k];
						}
					}
					
					articulosPALC.setArticulo(articulo);
					
					articulosPALC.setCentroDistribucion(cd_mas_cercano);
					
					articulosPALC.setProcesado(0);
						
					articulosPALC.setPalc(palc);
						
					palc.addArticulosPALC(articulosPALC);
				}
			}
		}
		
		try{
			manager.merge(palc);
			
			PALCVO ret = new PALCVO();
			ret = palc.getPALCVO();
			
			return ret;
		}catch (Exception e){
			
			manager.remove(palc);
			
			throw new ZaraException("No se pudo guardar el PALC " + e.toString());
		}
	}
	
	@SuppressWarnings("finally")
	public TiendaVO getTienda(String nombreTienda) throws ZaraException{
		Query query = manager.createQuery("SELECT t FROM Tienda t WHERE t.nombreTienda LIKE :nombreTienda");
		query.setParameter("nombreTienda", nombreTienda);
		
		Tienda tienda = null;
		
		try{
			tienda = (Tienda)query.getSingleResult();
		}catch(NonUniqueResultException e){
			throw new ZaraException(e.toString());
		}finally{
			if(tienda != null){
				return tienda.getTiendaVO(); 	
			}else{
				throw new ZaraException("No existe una Tienda para el nombre: " + nombreTienda);
			}
		}
	}
	
	private Tienda getTiendaInstance(String nombreTienda)throws NonUniqueResultException{
		Query query = manager.createQuery("SELECT t FROM Tienda t WHERE t.nombreTienda LIKE :nombreTienda");
		query.setParameter("nombreTienda", nombreTienda);
		
		Tienda tienda = (Tienda)query.getSingleResult();
		
		return tienda;
	}
	
	private float getDistancia(Tienda tienda, CentroDistribucion centroDistribucion){
		float distancia = 0;
		
		distancia = (float) Math.sqrt(Math.pow(tienda.getLatitud(), centroDistribucion.getLatitud()) + Math.pow(tienda.getLongitud(), centroDistribucion.getLongitud()));
		
		return distancia;
	}

	public Collection<PALCVO> setPALCS(Collection<PALCVO> palcs) throws ZaraException{
		
		Object[] articulosPALCArray = palcs.toArray();
		
		for (int i = 0; i < articulosPALCArray.length; i++){
			setPALC((PALCVO)articulosPALCArray[i]);
		}
		
		return palcs;
	}
	
	@SuppressWarnings({ "deprecation", "finally" })
	public Collection<ArticuloVO> getArticulosPedidosPorNTiendas(int nTiendas) throws ZaraException{
		 
		Collection<ArticuloVO> articulosVO = new HashSet<ArticuloVO>();
		
		Hashtable<Articulo, Integer> articulos = new Hashtable<Articulo, Integer>();
		
		java.util.Date date = new java.util.Date();
		java.util.Calendar aux_date = java.util.Calendar.getInstance();
		aux_date.add(java.util.Calendar.DATE, -15);
		
		java.util.Date limite_i = aux_date.getTime();
		
		java.util.Date limite_j = date;
		
		List palcs = null;
		
		try{
			palcs = manager.createQuery("SELECT p FROM PALC p").getResultList();
		}catch (Exception e){
			throw new ZaraException(e.toString());
		}finally{
			if (palcs.size() == 0){
				throw new ZaraException("No hay PALCS nuevos guardados en la base de datos");
			}else{
				for(int i = 0; i < palcs.size(); i++){
					PALC palc = (PALC) palcs.get(i);
					
					java.util.Date palc_date = new java.util.Date(palc.getFechaPALC().getTime());
				
					if((palc_date.after(limite_i))&&(palc_date.before(limite_j))){
						
						Object[] articulosPALC = palc.getArticulosPALC().toArray();
							
						for (int j = 0; j < articulosPALC.length; j++){
							ArticulosPALC articuloPALC = (ArticulosPALC) articulosPALC[j];
							if (articulos.containsKey(articuloPALC.getArticulo())){
								int value = articulos.get(articuloPALC.getArticulo());
								value = value ++;
							}else{
								articulos.put(articuloPALC.getArticulo(), 1);
							}
						}
						
					}
				}
				
				for (Enumeration e = articulos.keys(); e.hasMoreElements();)
			    {
					try{
						Object aux = e.nextElement();
						if (articulos.get(aux) <= nTiendas){
							Articulo articulo = (Articulo) aux;
							articulosVO.add(articulo.getArticuloVO());
						}
					}catch (Exception ex){
						throw new ZaraException(ex.toString());
					}
			    }
				
				return articulosVO;
			}
		}
	}			
}
